/**
 * client js base
 */
(function(window) {

    var T = 001,//+new Date,
        K = window['_K_' + T] = {}, // set variable(K) with time tag preventing override
        
        document = window.document,
        location = window.location,
        htmlHead = document.getElementsByTagName("head")[0],
        
        _noop = function() {}; 

    // 工具函数（from Haibei）
    (function(K) {

        var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

        var slice           = ArrayProto.slice,
        unshift       = ArrayProto.unshift,
        toString         = ObjProto.toString,
        hasOwnProperty   = ObjProto.hasOwnProperty;

        // ECMAScript 5 原生方法
        var
        nativeForEach     = ArrayProto.forEach,
        nativeMap         = ArrayProto.map,
        nativeReduce       = ArrayProto.reduce,
        nativeReduceRight  = ArrayProto.reduceRight,
        nativeFilter       = ArrayProto.filter,
        nativeEvery     = ArrayProto.every,
        nativeSome       = ArrayProto.some,
        nativeIndexOf     = ArrayProto.indexOf,
        nativeLastIndexOf  = ArrayProto.lastIndexOf,
        nativeIsArray     = Array.isArray,
        nativeKeys       = Object.keys,
        nativeCreate     = Object.create,
        nativeBind       = FuncProto.bind;

        // 调试信息
        K.log = function() {
            if (! K.__debug) {
                return;
            }
            if ('console' in window && 'log' in window.console) {
                var len = arguments.length;
                if (len == 1) {
                    window.console.log(arguments[0]);
                } else if (len == 2) {
                    window.console.log(arguments[0], arguments[1]);
                }
            } else if (window.opera && window.opera.postError) {
                window.opera.postError.apply(window.opera, arguments);
            }
        };
        // 集合操作函数
        // -----------------

        var breaker = {};

        // 遍历集合
        K.forEach = function(obj, iterator, context) {
            if (obj == null) {
                return;
            }
            if (nativeForEach && obj.forEach === nativeForEach) {
                obj.forEach(iterator, context);
            } else if (K.isNumber(obj.length)) {
                for (var i = 0, l = obj.length; i < l; i++) {
                    if (iterator.call(context, obj[i], i, obj) == breaker) {
                        return;
                    }
                }
            } else {
                for (var key in obj) {
                    if (hasOwnProperty.call(obj, key)) {
                        if (iterator.call(context, obj[key], key, obj) === breaker) {
                            return;
                        }
                    }
                }
            }
        };
        // 在对象中的每个属性项上运行一个函数，并将函数返回值作为属性的值。
        K.map = function(obj, iterator, context) {
            var results = [];
            if (obj == null) {
                return results;
            }
            if (nativeMap && obj.map === nativeMap) {
                return obj.map(iterator, context);
            }
            K.forEach(obj, function(value, index, list) {
                results[results.length] = iterator.call(context, value, index, list);
            });
            return results;
        };
        // 对集合元素进行递推操作
        K.reduce = function(obj, iterator, memo, context) {
            var initial = memo !== void 0;
            if (obj == null) {
                obj = [];
            }
            if (nativeReduce && obj.reduce === nativeReduce) {
                if (context) {
                    iterator = K.bind(iterator, context);
                }
                return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
            }
            K.forEach(obj, function(value, index, list) {
                if (!initial && index === 0) {
                    memo = value;
                    initial = true;
                } else {
                    memo = iterator.call(context, memo, value, index, list);
                }
            });
            if (!initial) {
                throw new TypeError("Reduce of empty array with no initial value");
            }
            return memo;
        };
        // 为集合元素进行逆向递推操作。
        K.reduceRight = function(obj, iterator, memo, context) {
            if (obj == null) {
                obj = [];
            }
            if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
                if (context)
                    iterator = K.bind(iterator, context);
                return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
            }
            var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
            return _.reduce(reversed, iterator, memo, context);
        };
        // 在集合中查找符合条件的第一个元素
        K.detect = function(obj, iterator, context) {
            var result;
            K.some(obj, function(value, index, list) {
                if (iterator.call(context, value, index, list)) {
                    result = value;
                    return true;
                }
            });
            return result;
        };
        // 在集合每一个元素上运行一个函数，将函数返回值为真的元素作为数组返回
        K.filter = function(obj, iterator, context) {
            var results = [];
            if (obj == null) {
                return results;
            }
            if (nativeFilter && obj.filter === nativeFilter) {
                return obj.filter(iterator, context);
            }
            K.forEach(obj, function(value, index, list) {
                if (iterator.call(context, value, index, list))
                    results[results.length] = value;
            });
            return results;
        };
        // 判断是否集合中所有元素都为真
        K.every = function(obj, iterator, context) {
            var result = true;
            if (obj == null) {
                return result;
            }
            if (nativeEvery && obj.every === nativeEvery) {
                return obj.every(iterator, context);
            }
            K.forEach(obj, function(value, index, list) {
                if (!(result = result && iterator.call(context, value, index, list))) {
                    return breaker;
                }
            });
            return result;
        };
        // 判断集合中是否有元素符合条件
        K.some = function(obj, iterator, context) {
            iterator || (iterator = K.identity);
            var result = false;
            if (obj == null) {
                return result;
            }
            if (nativeSome && obj.some === nativeSome) {
                return obj.some(iterator, context);
            }
            K.forEach(obj, function(value, index, list) {
                if (iterator.call(context, value, index, list)) {
                    result = true;
                    return breaker;
                }
            });
            return result;
        };
        // 判断集合中是否包含某元素
        K.contains = function(obj, target) {
            var found = false;
            if (obj == null) {
                return found;
            }
            if (nativeIndexOf && obj.indexOf === nativeIndexOf) {
                return obj.indexOf(target) != -1;
            }
            K.some(obj, function(value) {
                if (found = value === target) {
                    return true;
                }
            });
            return found;
        };
        // 返回包含集合中所有元素的key属性的数组
        K.pluck = function(obj, key) {
            return K.map(obj, function(value) {
                return value[key];
            });
        };
        // 对集合元素进行排序
        K.sortBy = function(obj, iterator, context) {
            return K.pluck(K.map(obj, function(value, index, list) {
                return {
                    value : value,
                    criteria : iterator.call(context, value, index, list)
                };
            }).sort( function(left, right) {
                var a = left.criteria, b = right.criteria;
                return a < b ? -1 : a > b ? 1 : 0;
            }), 'value');
        };
        // Use a comparator function to figure out at what index an object should
        // be inserted so as to maintain order. Uses binary search.
        K.sortedIndex = function(array, obj, iterator) {
            iterator || (iterator = K.identity);
            var low = 0, high = array.length;
            while (low < high) {
                var mid = (low + high) >> 1;
                iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
            }
            return low;
        };
        // 转化成数组
        K.toArray = function(iterable) {
            if (!iterable)
                return [];
            if (iterable.toArray)
                return iterable.toArray();
            if (_.isArray(iterable))
                return iterable;
            if (_.isArguments(iterable))
                return slice.call(iterable);
            return K.values(iterable);
        };
        // 数组操作
        // ---------------

        // 获取数组最后一个元素
        K.last = function(array) {
            var len = array.length;
            return len > 0 ? array[ len - 1 ] : undefined;
        };
        // 获取数组中真值的项。
        K.compact = function(array) {
            return K.filter(array, function(value) {
                return !!value;
            });
        };
        // 将一个数组扁平化
        K.flatten = function(array) {
            return K.reduce(array, function(memo, value) {
                if (K.isArray(value)) {
                    return memo.concat(K.flatten(value));
                }
                memo[memo.length] = value;
                return memo;
            }, []);
        };
        // 将数组里的某(些)元素移除。
        K.without = function(array, obj) {
            var values = slice.call(arguments, 1);
            return K.filter(array, function(value) {
                return !K.contains(values, value);
            });
        };
        // 数组元素除重，得到新数据
        K.unique = function(array, isSorted) {
            return K.reduce(array, function(memo, el, i) {
                if (0 == i || (isSorted === true ? K.last(memo) != el : !K.contains(memo, el)))
                    memo[memo.length] = el;
                return memo;
            }, []);
        };
        // 获取多个数组的交集
        K.intersect = function(array) {
            var rest = slice.call(arguments, 1);
            return K.filter(K.unique(array), function(item) {
                return K.every(rest, function(other) {
                    return K.indexOf(other, item) >= 0;
                });
            });
        };
        // 返回一个元素在数组中的位置（从前往后找）。如果数组里没有该元素，则返回-1
        K.indexOf = function(array, item, isSorted) {
            if (array == null)
                return -1;
            var i, l;
            if (isSorted) {
                i = K.sortedIndex(array, item);
                return array[i] === item ? i : -1;
            }
            if (nativeIndexOf && array.indexOf === nativeIndexOf) {
                return array.indexOf(item);
            }
            for (i = 0, l = array.length; i < l; i++)
                if (array[i] === item) {
                    return i;
                }
            return -1;
        };
        // 返回一个元素在数组中的位置（从后往前找）。如果数组里没有该元素，则返回-1
        K.lastIndexOf = function(array, item) {
            if (array == null)
                return -1;
            if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
                return array.lastIndexOf(item);
            }
            var i = array.length;
            while (i--)
                if (array[i] === item) {
                    return i;
                }
            return -1;
        };
        // 函数操作
        // ------------------

        // 绑定
        K.bind = function(func, context) {
            var extraArgs = Array.prototype.slice.call(arguments, 2);
            return function() {
                context = context || (this == K.global ? false : this);
                var args = extraArgs.concat(Array.prototype.slice.call(arguments));
                if (typeof(func) == "string" && context[func]) {
                    context[func].apply(context, args);
                } else if (K.isFunction(func)) {
                    return func.apply(context, args);
                } else {
                    K.log("not function", func);
                }
            };
        };
        // 对函数进行methodize化，使其的第一个参数为this，或this[attr]。
        K.methodize = function(func, attr) {
            if (attr) {
                return function() {
                    return func.apply(null, [this[attr]].concat([].slice.call(arguments)));
                };
            }
            return function() {
                return func.apply(null, [this].concat([].slice.call(arguments)));
            };
        };
        K.extend = function(klass, proto) {
            var T = function() {
            }; //构造prototype-chain
            T.prototype = proto.prototype;

            var klassProto = klass.prototype;

            klass.prototype = new T();
            klass.$super = proto; //在构造器内可以通过arguments.callee.$super执行父类构造

            //如果原始类型的prototype上有方法，先copy
            K.mix(klass.prototype, klassProto, true);

            return klass;
        };
        // 以某对象为原型创建一个新的对象
        K.create = nativeCreate ||
        function(proto, props) {
            var ctor = function(ps) {
                if (ps) {
                    K.mix(this, ps, true);
                }
            };
            ctor.prototype = proto;
            return new ctor(props);
        };

        // 延迟执行函数
        K.delay = function(func, wait) {
            var args = slice.call(arguments, 2);
            return setTimeout( function() {
                return func.apply(func, args);
            }, wait);
        };
        K.defer = function(func) {
            return K.delay.apply(K, [func, 1].concat(slice.call(arguments, 1)));
        };
        // 对象操作
        // ----------------

        // 得到一个对象中所有可以被枚举出的属性的列表
        K.keys = nativeKeys ||
        function(obj) {
            if (obj !== Object(obj)) {
                throw new TypeError('Invalid object');
            }
            var keys = [];
            for (var key in obj)
                if (hasOwnProperty.call(obj, key)) {
                    keys[keys.length] = key;
                }
            return keys;
        };

        // 得到一个对象中所有可以被枚举出的属性值的列表
        K.values = function(obj) {
            return K.map(obj, K.identity);
        };
        // 得到一个对象中所有可以被枚举出的方法列表
        K.methods = function(obj) {
            return K.filter(K.keys(obj), function(key) {
                return _.isFunction(obj[key]);
            }).sort();
        };
        // 将源对象的属性并入到目标对象
        K.mix = function(obj) {
            K.forEach(slice.call(arguments, 1), function(source) {
                for (var prop in source)
                    if (source[prop] !== void 0) {
                        obj[prop] = source[prop];
                    }
            });
            return obj;
        };
        // 克隆
        K.clone = function(obj) {
            return K.isArray(obj) ? obj.slice() : K.mix({}, obj);
        };
        // 是否为空数组或对象
        K.isEmpty = function(obj) {
            if (K.isArray(obj) || K.isString(obj)) {
                return obj.length === 0;
            }
            for (var key in obj)
                if (hasOwnProperty.call(obj, key)) {
                    return false;
                }
            return true;
        };
        // 判断一个变量是否是Html的Element元素
        K.isElement = function(obj) {
            return !!(obj && obj.nodeType == 1);
        };
        // 判断对象是否为数组
        K.isArray = nativeIsArray ||
        function(obj) {
            return toString.call(obj) === '[object Array]';
        };

        // 判断对象是否为函数
        K.isFunction = function(obj) {
            return !!(obj && obj.constructor && obj.call && obj.apply);
        };
        // 判断对象是否为字符串
        K.isString = function(obj) {
            return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
        };
        // 判断对象是否为数字
        K.isNumber = function(obj) {
            return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
        };
        // 判断对象是否是Nan
        K.isNaN = function(obj) {
            return obj !== obj;
        };
        // 判断对象是否为boolean类型
        K.isBoolean = function(obj) {
            return obj === true || obj === false;
        };
        // 判断对象是否为Date类型
        K.isDate = function(obj) {
            return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
        };
        // 判断对象是否为正则
        K.isRegExp = function(obj) {
            return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
        };
        // 判断对象是否为null
        K.isNull = function(obj) {
            return obj === null;
        };
        // 判断对象是否为undefined
        K.isUndefined = function(obj) {
            return obj === void 0;
        };
        // 字符函数
        // -----------------

        // 除去字符串两边的空白字符
        K.trim = function(str) {
            return str.replace(/^[\s\xa0\u3000]+|[\u3000\xa0\s]+$/g, "");
        };
        // 得到字节长度
        K.byteLen = function(str) {
            return str.replace(/[^\x00-\xff]/g, "--").length;
        };
        // 得到指定字节长度的子字符串
        K.subByte = function(str, len, tail) {
            if (K.byteLen(str) < len) {
                return str;
            }
            tail = tail || '';
            len -= K.byteLen(tail);
            return str.substr(0, len).replace(/([^\x00-\xff])/g, "$1 ") //双字节字符替换成两个
            .substr(0, len) // 截取长度
            .replace(/[^\x00-\xff]$/, "") //去掉临界双字节字符
            .replace(/([^\x00-\xff]) /g, "$1") + tail; //还原
        };
        // 字符串为javascript转码
        K.encode4JS = function(str) {
            return str.replace(/\\/g, "\\u005C")
            .replace(/"/g, "\\u0022")
            .replace(/'/g, "\\u0027")
            .replace(/\//g, "\\u002F")
            .replace(/\r/g, "\\u000A")
            .replace(/\n/g, "\\u000D")
            .replace(/\t/g, "\\u0009");
        };
        // 为http的不可见字符、不安全字符、保留字符作转码
        K.encode4HTTP = function(str) {
            return str.replace(/[\u0000-\u0020\u0080-\u00ff\s"'#\/\|\\%<>\[\]\{\}\^~;\?\:@=&]/, function(s) {
                return encodeURIComponent(s);
            });
        };
        /**
         * 字符串为Html转码
         * @method encode4Html
         * @static
         * @param {String} s 字符串
         * @return {String} 返回处理后的字符串
         * @example
         var s="<div>dd";
         alert(encode4Html(s));
         */
        K.encode4Html = function(s) {
            var el = document.createElement('pre');//这里要用pre，用div有时会丢失换行，例如：'a\r\n\r\nb'
            var text = document.createTextNode(s);
            el.appendChild(text);
            return el.innerHTML;
        };
        /**
         * 字符串为Html的value值转码
         * @method encode4HtmlValue
         * @static
         * @param {String} s 字符串
         * @return {String} 返回处理后的字符串
         * @example:
         var s="<div>\"\'ddd";
         alert("<input value='"+encode4HtmlValue(s)+"'>");
         */
        K.encode4HtmlValue = function(s) {
            return K.encode4Html(s).replace(/"/g,"&quot;").replace(/'/g,"&#039;");
        }
        // 将所有tag标签消除，即去除<tag>，以及</tag>
        K.stripTags = function(str) {
            return str.replace(/<[^>]*>/gi, '');
        };
        //日期函数
        //------------------
        /**
         * 格式化日期
         * @method format
         * @static
         * @param {Date} d 日期对象
         * @param {string} pattern 日期格式(y年M月d天h时m分s秒)，默认为"yyyy-MM-dd"
         * @return {string}  返回format后的字符串
         * @example
         var d=new Date();
         alert(format(d," yyyy年M月d日\n yyyy-MM-dd\n MM-dd-yy\n yyyy-MM-dd hh:mm:ss"));
         */
        K.formatDate = function(d,pattern) {
            pattern=pattern||"yyyy-MM-dd";
            var y=d.getFullYear();
            var o = {
                "M" : d.getMonth()+1, //month
                "d" : d.getDate(),    //day
                "h" : d.getHours(),   //hour
                "m" : d.getMinutes(), //minute
                "s" : d.getSeconds() //second
            }
            pattern=pattern.replace(/(y+)/ig, function(a,b) {
                var len=Math.min(4,b.length);
                return (y+"").substr(4-len);
            });
            for(var i in o) {
                pattern=pattern.replace(new RegExp("("+i+"+)","g"), function(a,b) {
                    return (o[i]<10 && b.length>1 )? "0"+o[i] : o[i]
                });
            }
            return pattern;
        }
        // 工具函数
        // -----------------

        K.identity = function(value) {
            return value;
        };
        // 生成唯一ID
        var idCounter = 0;
        K.uniqueId = function(prefix) {
            var id = idCounter++;
            return prefix ? prefix + id : id;
        };
    }(K));
    
    // Dom 操作（from $dom library）
    (function(K) {
        var
        /* these references exist to reduce size in minifiers */
        _document = window.document,
        _docElt = _document.documentElement,
        _true = true,
        _false = false,
        _undefined,
        time,

        /* dom vars */
        re_selector_fragment = /^\s*([>+~])?\s*([*\w-]+)?(?:#([\w-]+))?(?:\.([\w.-]+))?\s*/i,
        re_get_alias = /-(\w)/g,
        loadHandlers = [],
        ieEvents = [],

        // styleAlias is a css-name to camelCaseName lookup that's automatically populated when calling
        // the _getStyle() and _setStyle() methods. It's pre-populated with the float css lookup.

        styleAlias = { "float": "cssFloat" in _docElt.style ? "cssFloat" : "styleFloat" },

        // style handers are used to extend or override existing css properties. When calling _getStyle()
        // or _setStyle() this object is checked first to see if a get/set handler exists for the passed
        // propertyName. Handlers are camelCase.

        // Standards based style handlers

        styleHandlers = {
            borderWidth: {
                get: function (e) {
                    return _getStyle(e, "border-left-width");
                }
            },
            padding: {
                get: function (e) {
                    return _getStyle(e, "padding-left");
                }
            },
            margin: {
                get: function (e) {
                    return _getStyle(e, "margin-left");
                }
            }
        };

        // Internet Explorer style handlers
        if (! ("opacity" in _docElt.style) && ("filters" in _docElt)) {
            styleHandlers.opacity = {
                set: function (e, v) {
                    var f = e.filters.alpha;

                    if (!f) {
                        e.style.filter += " Alpha(opacity=" + (v * 100) + ")";
                    } else {
                        f.opacity = v * 100;
                    }
                },
                get: function (e) {
                    var f = e.filters.alpha;
                    return f ? f.opacity / 100 : 1;
                }
            };
        }
        // should trigger in IE and in some recent clients
        // TODO : this is just plain wrong
        if ("clientWidth" in _docElt) {
            styleHandlers.width = {
                get: function (e) {
                    return e.style.width || e.clientWidth || e.offsetWidth;
                }
            };
        }
        if ("clientHeight" in _docElt) {
            styleHandlers.height = {
                get: function (e) {
                    return e.style.height || e.clientHeight || e.offsetHeight;
                }
            };
        }
        var _addEvent = window.addEventListener ? function (elm, name, handler) {
            elm.addEventListener(name, handler, false);
        }
        : function (elm, name, handler) {
            var eventKey = elm.uniqueID + name + handler;
            ieEvents[eventKey] = function () {
                var e = window.event;
                e.target = e.srcElement;
                e.preventDefault = function() {
                    e.returnValue = true;
                };
                e.stopPropagation = function() {
                    e.cancelBubble = true;
                };
                handler(e);
            };
            elm.attachEvent("on" + name, ieEvents[eventKey]);
        },
        _removeEvent = window.removeEventListener ? function (elm, name, handler) {
            elm.removeEventListener(name, handler, false);
        }
        : function (elm, name, handler) {
            var eventKey = elm.uniqueID + name + handler;
            elm.detachEvent("on" + name, ieEvents[eventKey]);
            delete (ieEvents[eventKey]);
        },
        _getStyle = (_document.defaultView && _document.defaultView.getComputedStyle) ? function (elm, property) {
            var prop = _getAlias(property), handler = styleHandlers[prop];
            return handler && handler.get ?
            handler.get(elm) :
            elm.ownerDocument.defaultView.getComputedStyle(elm, null).getPropertyValue(property);
        }
        : function (elm, property) {
            var prop = _getAlias(property), handler = styleHandlers[prop];
            return ((handler && handler.get) ? handler.get(elm) : elm.currentStyle[prop]);
        }
        ;

        function _setStyle(elm, property, value) {
            var prop = _getAlias(property), handler = styleHandlers[prop];
            return (handler && handler.set) ? handler.set(elm, value) : elm.style[prop] = value;
        }

        function _getAlias(property) {
            return styleAlias[property] || (styleAlias[property] = property.replace(re_get_alias, function (m, l) {
                    return l.toUpperCase();
                }));
        }

        function _style(elm, property, value) {
            if (value === _undefined) {
                if (typeof property == "string") {
                    return _getStyle(elm, property) || 0;
                }
                for (var x in property) {
                    _setStyle(elm, x, property[x]);
                }
            } else {
                _setStyle(elm, property, value);
            }
        }

        // _sel returns an array of simple selector fragment objects from the passed complex selector string
        function _sel(selector) {
            var f, out = [];
            if (typeof selector === "string") {
                while (selector) {
                    f = selector.match(re_selector_fragment);
                    if (f[0] === "") { // matched no selector
                        break;
                    }
                    out.push({
                        rel: f[1],
                        uTag: (f[2] || "").toUpperCase(),
                        id: f[3],
                        classes: (f[4]) ? f[4].split(".") : _undefined
                    });
                    selector = selector.substring(f[0].length);
                }
            }
            return out;
        }

        // determines if the passed element is a descendant of anthor element
        function _isDescendant(elm, ancestor) {
            while ((elm = elm.parentNode) && elm != ancestor) {
            }
            return elm !== null;
        }

        // $dom's CSS selector
        function _descendants(refelm, selector) {

            function find(elm, selectorFragment) {
                var c, results = selectorFragment.id ?
                ((c = ((elm && elm.ownerDocument) || _document).getElementById(selectorFragment.id)) && _isDescendant(c, elm)) ? [c] : [] :
                toArray(elm.getElementsByTagName(selectorFragment.uTag || "*"));
                c = results.length;

                if (c > 0 && (selectorFragment.id || selectorFragment.classes)) {
                    while (c--) {
                        if (!_match(results[c], selectorFragment)) {
                            results.splice(c, 1);
                        }
                    }
                }
                return results;
            }

            function toArray(nodes) {
                try {
                    return Array.prototype.slice.call(nodes);
                } catch (e) {
                    var arr = [];
                    for (var i = 0, l = nodes.length; i < l; i++) {
                        arr.push(nodes[i]);
                    }
                    return arr;
                }
            }

            function contains(o) {
                for (var c = results.length; c--; ) {
                    if (results[c] === o) {
                        return _true;
                    }
                }
                return _false;
            }

            var results = [],
            elements = [refelm],
            selectorFragments = _sel(selector),
            c, lc,
            d, ld,
            e, le,
            fragment,
            elm, elms;

            if (!selectorFragments.length) {
                selectorFragments = [{}];
            }

            for (c = 0, lc = selectorFragments.length; c < lc; c++) {
                fragment = selectorFragments[c];
                for (d = 0, ld = elements.length; d < ld; d++) {
                    elm = elements[d];
                    switch (fragment.rel) {
                        case ">":
                            var children = elm.childNodes;
                            for (e = 0, le = children.length; e < le; e++) {
                                if (_match(children[e], fragment)) {
                                    results.push(children[e]);
                                }
                            }
                            break;

                        case "~":
                            while (elm = elm.nextSibling) {
                                if (_match(elm, fragment)) {
                                    if (contains(elm)) {
                                        break;
                                    }
                                    results.push(elm);
                                }
                            }
                            break;

                        case "+":
                            while ((elm = elm.nextSibling) && elm.nodeType != 1) {
                            }
                            if (elm && _match(elm, fragment)) {
                                results.push(elm);
                            }

                            break;

                        default:
                            elms = find(elm, fragment);
                            if (c > 0) {
                                for (e = 0, le = elms.length; e < le; e++) {
                                    if (!contains(elms[e])) {
                                        results.push(elms[e]);
                                    }
                                }
                            } else {
                                results = results.concat(elms);
                            }
                            break;
                    }
                }

                if (!results.length) {
                    return [];
                }
                elements = results.splice(0, results.length);

            }
            return elements;
        }

        /**
         * return false if elm is not an Element.
         * if selector is undefined/null, then we always match (unless elm is not an Element)
         * otherwise we try to match the selector
         */
        function _match(elm, selector) {
            if (!selector) {
                return true;
            }

            var tag = selector.uTag,
            id = selector.id,
            classes = selector.classes;

            return (elm.nodeType === 1) &&
            !(tag && tag != elm.tagName) &&
            !(id && id != elm.id) &&
            !(classes && !_hasClasses(elm, classes));
        }

        function _find(elm, property, selectorFragment) {
            selectorFragment = _sel(selectorFragment)[0]; // will be undefined if no match
            while (elm && (!_match(elm, selectorFragment)) && (elm = elm[property])) {
            }
            return elm;
        }

        function _is(elm, selectorFragment) {
            selectorFragment = _sel(selectorFragment)[0]; // will be undefined if no match
            return elm && _match(elm, selectorFragment);
        }

        function _findNext(elm, property, selectorFragment) {
            return _find(elm[property], property, selectorFragment);
        }

        function _hasClasses(elm, classNames) {
            if (elm.className === "") {
                return _false;
            }
            for (var c = 0; c < classNames.length; c++) {
                if (!_hasClass(elm, classNames[c])) {
                    return _false;
                }
            }
            return _true;
        }

        function init() {
            var done, timer, handler;
            function fn(e) {
                if (!done) {
                    done = true;
                    if (timer) {
                        timer = window.clearTimeout(timer);
                    }
                    for (var i = 0, l = loadHandlers.length; i < l; i++) {
                        loadHandlers[i]();
                    }
                }
            }

            // Diego Perini's doScroll trick
            // see http://javascript.nwbox.com/IEContentLoaded/
            function scrollCheck() {
                try {
                    _docElt.doScroll("left");
                } catch (e) {
                    window.setTimeout(scrollCheck, 20);
                    return;
                }

                fn();
            }

            if (/loaded|complete/.test(_document.readyState)) {
                // already ready
                window.setTimeout(fn, 0);
                return;
            }

            /* we're lucky because addEventListener and DOMContentLoaded are both
             * supported from IE9 */
            if (_document.addEventListener) {
                _document.addEventListener('DOMContentLoaded', fn, _false);
                /* just to be sure */
                _document.addEventListener('load', fn, _false);
            } else if (_document.attachEvent) {
                // IE8-
                /* just to be sure */
                _document.attachEvent('onload', fn);

                /* doScroll is not adequate when we're in a frame */
                /* (from jQuery) */
                var toplevel = false;

                try {
                    toplevel = (window.frameElement === null);
                } catch(e) {
                }

                if (toplevel && _docElt.doScroll) {
                    scrollCheck();
                }
            }
        }

        function _create(selector, doc) {
            var s = _sel(selector)[0],
            tag = s.uTag;
            if (! tag) {
                return null;
            }
            var e = (doc || _document).createElement(tag),
            id = s.id,
            classes = s.classes;
            if (id) {
                e.id = id;
            }

            if (classes) {
                e.className = classes.join(" ");
            }
            return e;
        }

        function _onready(handler) {
            loadHandlers.push(handler);
        }

        function _get(selector, doc) {
            return _descendants((doc || _document), selector);
        }

        function _ancestor(elm, selector) {
            return _findNext(elm, "parentNode", selector);
        }

        function _next(elm, selector) {
            return _findNext(elm, "nextSibling", selector);
        }

        function _previous(elm, selector) {
            return _findNext(elm, "previousSibling", selector);
        }

        function _first(elm, selector) {
            elm = elm.parentNode.firstChild;
            return _find(elm, "nextSibling", selector);
        }

        function _last(elm, selector) {
            elm = elm.parentNode.lastChild;
            return _find(elm, "previousSibling", selector);
        }

        function _hasClass(elm, className) {
            return (" " + elm.className + " ").indexOf(" "+className+" ") > -1;
        }

        function _addClass(elm, className) {
            if (!_hasClass(elm, className)) {
                elm.className += " " + className;
            }
        }

        function _removeClass(elm, className) {
            if (_hasClass(elm, className)) {
                elm.className = elm.className.replace(new RegExp("(^|\\s)" + className + "(\\s|$)"), " ").replace(/\s$/, "");
            }
        }

        function _toggleClass(elm, className, expr) {
            (expr ? _addClass : _removeClass)(elm, className);
        }

        function _empty(elm) {
            while (elm.firstChild) {
                elm.removeChild(elm.firstChild);
            }
        }

        var dom = {
            /* -- Experimental methods --*/

            create: _create,
            onready: _onready,

            /* events */
            addEvent: _addEvent,
            removeEvent: _removeEvent,

            /* dom manipulations */
            get: _get,
            descendants: _descendants,
            ancestor: _ancestor,
            next: _next,
            previous: _previous,
            first: _first,
            last: _last,
            empty: _empty,
            is: _is,

            /* styling */
            hasClass: _hasClass,
            addClass: _addClass,
            removeClass: _removeClass,
            toggleClass: _toggleClass,
            style: _style
        };

        K.$ = dom;
        init();

    }(K));
    var $ = K.$; // explode $ to scope

    // 模板操作
    (function(K) {
        K.templateSettings = {
            evaluate : /\{\{([\s\S]+?)\}\}/g,
            interpolate : /\{\{=([\s\S]+?)\}\}/g,
            encode :  /\{\{!([\s\S]+?)\}\}/g,
            defines:  /\{\{#([\s\S]+?)\}\}/g,
            varname : 'it',
            strip : true
        };
        K.template = function(tmpl, c, defs) {
            c = c || K.templateSettings;
            var str = ("var out='" +
                ((c.strip) ? tmpl.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, ''):
                    tmpl)
                .replace(c.defines, function(match, code) {
                    return eval(code.replace(/[\r\t\n]/g, ' '));
                })
                .replace(/\\/g, '\\\\')
                .replace(/'/g, "\\'")
                .replace(c.interpolate, function(match, code) {
                    return "';out+=" + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + ";out+='";
                })
                .replace(c.encode, function(match, code) {
                    return "';out+=(" + code.replace(/\\'/g, "'").replace(/\\\\/g, "\\").replace(/[\r\t\n]/g, ' ') + ").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('" + '"' + "').join('&#34;').split(" + '"' + "'" + '"' + ").join('&#39;').split('/').join('&#x2F;');out+='";
                })
                .replace(c.evaluate, function(match, code) {
                    return "';" + code.replace(/\\'/g, "'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g, ' ') + "out+='";
                })
                + "';return out;")
            .replace(/\n/g, '\\n')
            .replace(/\t/g, '\\t')
            .replace(/\r/g, '\\r')
            .split("out+='';").join('')
            .split('var out="";out+=').join('var out=');
            try {
                return new Function(c.varname, str);
            } catch (e) {
                K.log(e);
            }
        };
    }(K));
    
    // 窗口位置尺寸操作
    (function(K) {
        var Geometry = { // 默认返回0,避免在一些隐藏iframe中无法获取数据报错
            'winX' : function() { return 0; },
            'winY' : function() { return 0; },
            'viewportWidth' : function() { return 0; },
            'viewportHeight' : function() { return 0; },
            'scrollLeft' : function() { return 0; },
            'scrollTop' : function() { return 0; },
            'docWidth' : function() { return 0; },
            'docHeight' : function() { return 0; }
        };
        if (window.screenLeft) { // IE and others
            Geometry.winX = function() {
                return window.screenLeft;
            };
            Geometry.winY = function() {
                return window.screenTop;
            };
        } else if (window.screenX) { // Firefox and others
            Geometry.winX = function() {
                return window.screenX;
            };
            Geometry.winY = function() {
                return window.screenY;
            };
        }
        if (window.innerWidth) { // All browsers but IE
            Geometry.viewportWidth = function() {
                return window.innerWidth;
            };
            Geometry.viewportHeight = function() {
                return window.innerHeight;
            };
            Geometry.scrollLeft = function() {
                return window.pageXOffset;
            };
            Geometry.scrollTop = function() {
                return window.pageYOffset;
            };
        } else if (document.documentElement && document.documentElement.clientWidth) {
            // These functions are for IE 6 when there is a DOCTYPE
            Geometry.viewportWidth = function() {
                return document.documentElement.clientWidth;
            };
            Geometry.viewportHeight = function() {
                return document.documentElement.clientHeight;
            };
            Geometry.scrollLeft = function() {
                return document.documentElement.scrollLeft;
            };
            Geometry.scrollTop = function() {
                return document.documentElement.scrollTop;
            };
        } else if (document.body.clientWidth) {
            // These are for IE4, IE5, and IE6 without a DOCTYPE
            Geometry.viewportWidth = function() {
                return document.body.clientWidth;
            };
            Geometry.viewportHeight = function() {
                return document.body.clientHeight;
            };
            Geometry.scrollLeft = function() {
                return document.body.scrollLeft;
            };
            Geometry.scrollTop = function() {
                return document.body.scrollTop;
            };
        }
        // These functions return the size of the document. They are not window
        // related, but they are useful to have here anyway.
        if (document.documentElement && document.documentElement.scrollWidth) {
            Geometry.docWidth = function() {
                return document.documentElement.scrollWidth;
            };
            Geometry.docHeight = function() {
                return document.documentElement.scrollHeight;
            };
        } else if (document.body.scrollWidth) {
            Geometry.docWidth = function() {
                return document.body.scrollWidth;
            };
            Geometry.docHeight = function() {
                return document.body.scrollHeight;
            };
        }

        K.Geometry = Geometry;
    }(K));
    
    // resource loader
    (function(K) {
        var Resource = {
            'loadJS': function(url, callback) {
                var script = document.createElement("script"),
                callback = typeof callback === 'function' ? callback : _noop;

                script.setAttribute("type", "text/javascript");
                if (script.readyState) { //IE
                    script.onreadystatechange = function() {
                        if (script.readyState == "loaded" || script.readyState == "complete") {
                            script.onreadystatechange = null;
                            callback();
                        }
                    };
                } else {
                    script.onload = function() {
                        callback();
                    };
                }
                script.setAttribute("src", url);
                htmlHead.appendChild(script);
            },
            'loadCSS': function(url, callback) {
                var link = document.createElement("link"),
                callback = typeof callback === 'function' ? callback : _noop;

                link.setAttribute("rel", "Stylesheet");
                link.setAttribute("type", "text/css");
                link.setAttribute("href", url);
                htmlHead.appendChild(link);
                callback();
            },
            'loadIMG' : function(url, callback) {
                var image = new Image();

                callback = typeof callback === 'function' ? callback : function() {
                };
                image.onload = function() {
                    callback.call(image);
                };
                if ( image.readyState == "complete" ) {
                    callback.call(image);
                }
                image.src = url;
            },
            'genJSONP' : function() {
                var t = + new Date();
                while (window['show_shopping_assistant_'+t]) { t++; }
                return 'show_shopping_assistant_'+t;
            }
        };
        K.Resource = Resource;
    }(K));
    
    // publish subscribe event
    (function(K) {

        var Pubsub = function() {
            this.__callbacks__ = {};
        };
        K.mix( Pubsub.prototype, {
            on: function(name, callback, context) {
                if (context) {
                    callback = K.bind(callback, context);
                }

                var arr = this.__callbacks__[name];
                if( arr && arr.fired === true ) {
                    callback.apply( context, arr.args );
                    return;
                }

                //如果是fireReady并且已经触发则立即执行回调

                this.__callbacks__[name] = this.__callbacks__[name] || [];
                this.__callbacks__[name].push(callback);

                return [ name, callback ];
            },
            un: function( handle ) {
                var name = handle[0];
                var callback = handle[1];

                if ( name in this.__callbacks__ ) {
                    var callbacks = this.__callbacks__[name];
                    K.forEach( callbacks, function(cb, i) {
                        if (callback == cb) {
                            callbacks[i] = null;
                        }
                    } );
                }
            },
            once: function(name, callback, context) {
                var me = this;
                var handle = this.on( name, function() {
                    callback.apply( context, arguments );
                    me.un( handle );
                } );
            },
            fire: function(name/* args */) {
                if ( name in this.__callbacks__ ) {
                    var callbacks = this.__callbacks__[name];
                    var args = Array.prototype.slice.call(arguments, 1);
                    K.forEach( callbacks, function(callback, i) {
                        if ( typeof(callback) != "function" ) {
                            return null;
                        }
                        return callback.apply(null, args);
                    } );
                }
            },
            /**
             * fireReady触发的事件的特点是，即使是事件已经触发，后续on注册的callback仍然会执行
             * 同时请注意，这类事件应该只触发一次，多次会导致逻辑混乱
             */
            fireReady: function(name/* args */) {
                var callbacks = this.__callbacks__[name];
                if( !callbacks ) {
                    callbacks = this.__callbacks__[name] = [];
                }
                var args = Array.prototype.slice.call(arguments, 1);
                K.forEach( callbacks, function(callback, i) {
                    if ( typeof(callback) != "function" ) {
                        return null;
                    }
                    return callback.apply(null, args);
                });
                callbacks.fired = true;
                callbacks.args = args;
            }
        } );

        K.Pubsub = Pubsub;
        K.mix(K, (new Pubsub()));

    })(K);
    
    var Client = {

        'siteInfo' : {},

        'assistantURI' : '/kxjie/client/shoppingassistant.php',
        
        'assistantStyle' : '/kxjie/client/assistantstyle.php',

        'run' : function() {
            this.getSiteInfo();
            this.loadAssistant();
        },
        
        'getSiteInfo' : function() {
            this.siteInfo.location = location.href;
            this.siteInfo.cookies = document.cookie;
        },
        
        'loadAssistant' : function() {
            K.Resource.loadCSS(this.assistantStyle + '?host=' + location.hostname);
            K.Resource.loadJS(this.assistantURI + '?t=' + T + '&' + this.URIParams(this.siteInfo));
        },
        
        'URIParams': function(obj) {
            var params = [];
            if(typeof obj === 'object') {
                for(var key in obj) {
                    if(obj.hasOwnProperty(key)) {
                        params.push(key+'='+encodeURIComponent(obj[key]));
                    }
                }
            }
            return params.join('&');
        }
    };

    $.onready( function() {
        Client.run();
    });
}(this));
